﻿using _698._45Tool.Utils;
using ClosedXML.Excel;
using CommonServiceLocator;
using Communication;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Jn698._45GWTool.Communication;
using Jn698._45GWTool.Services;
using Jn698._45GWTool.Settings;
using Jn698._45GWTool.Views;
using Jn698._45Tool.Utils;
using Microsoft.Win32;
using nblTool.utils;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using TouchSocket.Core;
using WebFirst.Entities;
using WindowsFormsApp1.Utils;

namespace Jn698._45GWTool.ViewModels.Controls
{
    public class MeterArchivesViewModel:ViewModelBase
    {
		private MeterInfoService MeterInfoService = new MeterInfoService();
        private SerialPortHelper serialPortHelper = SerialPortHelper.Instance;
        private TcpHelper tcpHelper = TcpHelper.Instance;
        public MeterArchivesViewModel()
        {
			MeterInfoList = new ObservableCollection<MeterInfo>(MeterInfoService.Select());
            MeterInfoList = new ObservableCollection<MeterInfo>(MeterInfoList.OrderBy(item => item.SeqNo));
            ConfigNumber = 1;
			MeterTotalNumber = MeterInfoList.Count;
        }

        private bool satae = true;

        public bool State
        {
            get { return satae; }
            set { Set(ref satae, value); }
        }
        private int configNumber;

		public int ConfigNumber
		{
			get { return configNumber; }
			set { configNumber = value; RaisePropertyChanged(); }
		}

        private int selectedMeterInfo;

        public int SelectedMeterInfo
        {
            get { return selectedMeterInfo; }
            set { selectedMeterInfo = value; RaisePropertyChanged(); }
        }


        private int meterTotalNumber;

		public int MeterTotalNumber
		{
			get { return meterTotalNumber; }
			set { meterTotalNumber = value; RaisePropertyChanged(); }
		}


		private ObservableCollection<MeterInfo> meterInfoList;

		public ObservableCollection<MeterInfo> MeterInfoList
        {
			get { return meterInfoList; }
			set { meterInfoList = value; RaisePropertyChanged(); }
		}

		public string GetMeterArFrame(MeterInfo meterInfo)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("020412");
			stringBuilder.Append(meterInfo.SeqNo.GetValueOrDefault().ToString("X4"));
			stringBuilder.Append("020A55");
            if (meterInfo.CommuAddr.Length % 2 != 0)
            {
                meterInfo.CommuAddr = meterInfo.CommuAddr.PadRight(meterInfo.CommuAddr.Length + 1, 'F');
            }
            stringBuilder.Append((meterInfo.CommuAddr.Length/2 + 1).ToString("X2"));
            stringBuilder.Append((meterInfo.CommuAddr.Length / 2 - 1).ToString("X2"));
			stringBuilder.Append(meterInfo.CommuAddr);
            stringBuilder.Append("16");
            if (meterInfo.Baudrate.Equals("11"))
            {
                stringBuilder.Append("FF");
            }
            else
            {
                stringBuilder.Append(meterInfo.Baudrate.GetValueOrDefault().ToString("X2"));
            }
            
            stringBuilder.Append("16");
            stringBuilder.Append(meterInfo.ProtocolType.GetValueOrDefault().ToString("X2"));
            stringBuilder.Append("51");
			stringBuilder.Append(meterInfo.Port);
            stringBuilder.Append("09");
            stringBuilder.Append((meterInfo.CommuCode.Length/2).ToString("X2"));
            stringBuilder.Append(meterInfo.CommuCode);
            stringBuilder.Append("11");
            stringBuilder.Append(int.Parse(meterInfo.TarriffNum).ToString("X2"));
            stringBuilder.Append("11");
            stringBuilder.Append(int.Parse(meterInfo.UserType).ToString("X2"));
            stringBuilder.Append("16");
            stringBuilder.Append(meterInfo.WireMode.GetValueOrDefault().ToString("X2"));
            stringBuilder.Append("12");
            
            stringBuilder.Append(((int)(double.Parse(meterInfo.RatedVoltage) * 10)).ToString("X4"));
            stringBuilder.Append("12");
            stringBuilder.Append(((int)(double.Parse(meterInfo.RatedCurrent) * 10)).ToString("X4"));
            stringBuilder.Append("020455");
            stringBuilder.Append((meterInfo.CollectAddr.Length / 2 + 1).ToString("X2"));
            stringBuilder.Append((meterInfo.CollectAddr.Length / 2 - 1).ToString("X2"));
            stringBuilder.Append(meterInfo.CollectAddr);
            stringBuilder.Append("09");
            if (meterInfo.AssetNumber.Length % 2 != 0)
            {
                meterInfo.AssetNumber = meterInfo.AssetNumber.PadLeft(meterInfo.AssetNumber.Length + 1, '0');
            }
            stringBuilder.Append((meterInfo.AssetNumber.Length/2).ToString("X2"));
            stringBuilder.Append(meterInfo.AssetNumber);
            stringBuilder.Append("12");
            stringBuilder.Append(int.Parse(meterInfo.Pt).ToString("X4"));
            stringBuilder.Append("12");
            stringBuilder.Append(int.Parse(meterInfo.Ct).ToString("X4"));
            stringBuilder.Append("0100");
            if (TerminalSettings.Instanse.TimeTagFlag)
            {
                stringBuilder.Append("01");
                stringBuilder.Append(StringUtils.DateTime2String(DateTime.Now));
                stringBuilder.Append(TerminalSettings.Instanse.TimeTagData);

            }
            else
            {
                stringBuilder.Append("00");
            }
            return stringBuilder.ToString();
		}

        private async Task awitTCPRecv(int timeOutSec)
        {
            using (var tokenSource = new CancellationTokenSource())
            {

                var startTime = DateTime.Now;
                while (true)
                {
                    if ((DateTime.Now - startTime) >= TimeSpan.FromSeconds(timeOutSec))
                    {
                        tokenSource.Cancel();
                    }
                    if (tokenSource.IsCancellationRequested)
                    {
                        return;
                    }
                    if (tcpHelper.isComplete == true)
                    {
                        return;
                    }
                    await Task.Delay(TimeSpan.FromMilliseconds(10));
                }
            }
        }
        public async Task<bool> SendFrameAsync(int num)
        {
            bool result_flag = false;
            string frame = "";
            string UserData = "";
            byte[] byteAddress = StringUtils.strToHexByte(MainViewModel.selectedDevice.DeviceAddress);
            List<byte> APDU;

            UserData = "0701006000800001";

            var selectedList = MeterInfoList.Where(item => item.IsSelect == true).ToList();
            //int num = ConfigNumber > selectedList.Count ? selectedList.Count : ConfigNumber;
            UserData += num.ToString("X2");
            for (int i = 0; i < num; i++)
            {
                if (i >= selectedList.Count)
                {
                    return false;
                }
                UserData += GetMeterArFrame(selectedList[i]);
            }
            APDU = MessageGenerationModule.GetSecuriityFrame(StringUtils.hexStringToBytes(UserData.Replace(" ", string.Empty)).ToList(), ServiceLocator.Current.GetInstance<MainViewModel>().SecuritySelectedIndex);
            //定义临时字节列表
            List<byte> temp = new List<byte>();

            temp.Add(0x68);
            //长度域
            short length = (short)(2 + 1 + 1 + (short)byteAddress.Length + 1 + 2 + (short)APDU.Count + 2);
            //FrameLen = string.Format("{0:X2}{1:X2}", length & 0x00ff, length >> 8);
            byte[] byteLength = BitConverter.GetBytes(length);

            temp.AddRange(byteLength);

            //控制域

            //byte control = StringUtils.string_2_BCD(Control)[0];
            temp.Add(0x43);

            //地址域
            //服务器地址SA
            byte addressLen = (byte)(byteAddress.Length - 1);
            if (MainViewModel.selectedDevice.DeviceAddress.Contains("A") || MainViewModel.selectedDevice.DeviceAddress.Contains("a"))
            {
                addressLen |= 0x40;
            }
            switch (TerminalSettings.Instanse.LogicAddressSelected)
            {
                case 1:
                    addressLen |= 0x10;
                    break;
                case 2:
                    addressLen |= 0x20;
                    break;
                case 3:
                    addressLen |= 0x30;
                    break;
                case 0:
                default:
                    break;
            }
            //temp.Add((byte)(byteAddress.Length - 1));
            temp.Add(addressLen);
            Array.Reverse(byteAddress);
            temp.AddRange(byteAddress);

            //客户机地址CA
            byte ca = 0x11;
            temp.Add(ca);

            //帧头校验HCS
            //HCS = ByteUtils.bytesToHexString(CheckSum.CRC16(temp, 1));
            temp.AddRange(CheckSum.CRC16(temp, 1));

            //链路用户数据
            temp.AddRange(APDU);

            //帧校验FCS
            //FCS = ByteUtils.bytesToHexString(CheckSum.CRC16(temp, 1));
            temp.AddRange(CheckSum.CRC16(temp, 1));

            //结束字符
            temp.Add(0x16);
            frame = ByteUtils.bytesToHexString(temp);


            byte[] b = StringUtils.hexStringToBytes(frame);
            string msgStr = "";
            for (int i = 0; i < b.Length; i++)
            {
                msgStr += b[i].ToString("X2") + " ";
            }
            Messenger.Default.Send<string>($"发送帧({DateTime.Now.ToString()})：{msgStr}", "SendMessage");
            switch (CommViewModel.selectedCommType)
            {
                case "串口":
                    serialPortHelper.SendDataMethod(b);
                    await Task.Run(() => result_flag=serialPortHelper.DataReceiveFunction());
                    break;
                case "GPRS":
                    tcpHelper.isComplete = false;
                    tcpHelper.SendData(MainViewModel.selectedDevice.DeviceAddress, b);
                    await awitTCPRecv(5);
                    result_flag = tcpHelper.isComplete;
                    break;
                default:
                    break;
            }
            return result_flag;
            /*                    serialPortHelper.SendDataMethod(b);
                                bool result = false;
                                await Task.Run(() => result = serialPortHelper.DataReceiveFunction());*/

        }
        public RelayCommand EditCommand
        {
            get
            {
                var command = new RelayCommand(() =>
                {
                    SelectedMeterInfo = -1;
                    EditMeterArView editMeterArView = new EditMeterArView();
                    
                    editMeterArView.ShowDialog();
                });
                return command;
            }
        }

        public RelayCommand SendCommand
        {
            get
            {
                var command = new RelayCommand( async () =>
                {
                    
                    if (MainViewModel.selectedDevice == null)
                    {
                        MessageBox.Show("请选择设备");
                        return;
                    }
                    
                    switch (ServiceLocator.Current.GetInstance<MainViewModel>().SecuritySelectedIndex)
                    {

                        //明文+RN_MAC
                        case 2:
                        //明文+SID_MAC
                        case 3:
                        //密文+SID
                        case 4:
                        //密文+SID_MAC
                        case 5:
                            if (string.IsNullOrWhiteSpace(SendModule.SessionInitKey))
                            {
                                MessageBox.Show("请先建立应用连接");
                                return;
                            }
                            break;
                        //明文
                        case 0:
                        //明文+RN
                        case 1:
                        default:
                            break;
                    }
                    State = false;
                    var selectedList = MeterInfoList.Where(item => item.IsSelect == true).ToList();
                    for (int i = 0; i < selectedList.Count; i+=ConfigNumber)
                    {
                        if (i>= selectedList.Count)
                        {
                            break;
                        }
                        if (!await SendFrameAsync(ConfigNumber))
                        {
                            break;
                        }
                    }
                    
                    State = true;


                });
                return command;
            }
        }

        #region Edit
        public RelayCommand ExportXMLCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    XmlHelper.ExportToXml(MeterInfoList.ToList(), "ExportToXml.xml");
                    SaveFileDialog saveDialog = new SaveFileDialog
                    {
                        Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*",
                        Title = "Save XML File",
                        /*FileName= "电表档案"*/
                    };

                    if (saveDialog.ShowDialog() == true)
                    {
                        // 如果用户选择了路径，保存工作簿到该路径
                        XmlHelper.ExportToXml(MeterInfoList.ToList(), saveDialog.FileName);
                        MessageBox.Show("保存成功");
                    }
                });
            }
        }
        public RelayCommand LoadXMLCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    try
                    {
                        OpenFileDialog openFileDialog = new OpenFileDialog
                        {
                            Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*"
                        };
                        if (openFileDialog.ShowDialog() == true)
                        {
                            Task.Run(() =>
                            {
                                string filePath = openFileDialog.FileName;
                                MeterInfoService.Delete();
                                Application.Current.Dispatcher.Invoke(() => { MeterInfoList.Clear(); });

                                var list = XmlHelper.LoadItemsFromXml<MeterInfo>(openFileDialog.FileName);
                                for (int i = 0; i < list.Count; i++)
                                {
                                    //MeterInfoList.Add(list[i]);
                                    Application.Current.Dispatcher.Invoke(() => { meterInfoList.Add(list[i]); });
                                }
                                MeterInfoService.Insert(MeterInfoList.ToList());
                                
                            });
                            
                        }
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                    
                });
            }
        }

        public RelayCommand ExportExcelCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    try
                    {
                        using (var workbook = new XLWorkbook())
                        {
                            // 添加一个工作表
                            var worksheet = workbook.AddWorksheet("Sheet1");

                            // 设置标题行
                            worksheet.Row(1).Style.Font.Bold = true; // 标题字体加粗
                            worksheet.Row(1).Style.Fill.BackgroundColor = XLColor.AliceBlue; // 标题背景颜色
                            worksheet.Row(1).Style.NumberFormat.Format = "@";
                            // 添加标题

                            worksheet.Cell(1, 1).Value = "配置序号";
                            worksheet.Cell(1, 2).Value = "通信地址";
                            worksheet.Cell(1, 3).Value = "波特率";
                            worksheet.Cell(1, 4).Value = "规约类型";
                            worksheet.Cell(1, 5).Value = "端口";
                            worksheet.Cell(1, 6).Value = "通信密码";
                            worksheet.Cell(1, 7).Value = "费率个数";
                            worksheet.Cell(1, 8).Value = "用户类型";
                            worksheet.Cell(1, 9).Value = "接线方式";
                            worksheet.Cell(1, 10).Value = "额定电压";
                            worksheet.Cell(1, 11).Value = "额定电流";
                            worksheet.Cell(1, 12).Value = "采集器地址";
                            worksheet.Cell(1, 13).Value = "资产号";
                            worksheet.Cell(1, 14).Value = "PT";
                            worksheet.Cell(1, 15).Value = "CT";

                            // 设置单元格的格式为字符串

                            //添加内容
                            for (int i = 0; i < MeterInfoList.Count; i++)
                            {
                                worksheet.Row(i + 2).Style.NumberFormat.Format = "@";
                                MeterInfo meterInfo = MeterInfoList[i];
                                worksheet.Cell(i + 2, 1).Value = meterInfo.SeqNo.ToString();
                                worksheet.Cell(i + 2, 2).Value = meterInfo.CommuAddr;
                                worksheet.Cell(i + 2, 3).Value = meterInfo.Baudrate.ToString();
                                worksheet.Cell(i + 2, 4).Value = meterInfo.ProtocolType.ToString();
                                worksheet.Cell(i + 2, 5).Value = meterInfo.Port;
                                worksheet.Cell(i + 2, 6).Value = meterInfo.CommuCode;
                                worksheet.Cell(i + 2, 7).Value = meterInfo.TarriffNum;
                                worksheet.Cell(i + 2, 8).Value = meterInfo.UserType;
                                worksheet.Cell(i + 2, 9).Value = meterInfo.WireMode.ToString();
                                worksheet.Cell(i + 2, 10).Value = meterInfo.RatedVoltage;
                                worksheet.Cell(i + 2, 11).Value = meterInfo.RatedCurrent;
                                worksheet.Cell(i + 2, 12).Value = meterInfo.CollectAddr;
                                worksheet.Cell(i + 2, 13).Value = meterInfo.AssetNumber;
                                worksheet.Cell(i + 2, 14).Value = meterInfo.Pt;
                                worksheet.Cell(i + 2, 15).Value = meterInfo.Ct;
                            }
                            // 调整列宽以适应内容
                            worksheet.Columns().AdjustToContents();

                            // 保存工作簿
                            SaveFileDialog saveDialog = new SaveFileDialog
                            {
                                Filter = "Excel Workbook (*.xlsx)|*.xlsx|All Files (*.*)|*.*",
                                Title = "Save Excel File",
                                /*FileName= "电表档案"*/
                            };

                            if (saveDialog.ShowDialog() == true)
                            {
                                // 如果用户选择了路径，保存工作簿到该路径
                                workbook.SaveAs(saveDialog.FileName);
                                MessageBox.Show("保存成功");
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                    
                });
            }
        }
        public RelayCommand LoadExcelCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    try
                    {
                        OpenFileDialog openFileDialog = new OpenFileDialog
                        {
                            Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*"
                        };

                        if (openFileDialog.ShowDialog() == true)
                        {
                            Task.Run(() =>
                            {
                                string filePath = openFileDialog.FileName;
                                MeterInfoService.Delete();
                                Application.Current.Dispatcher.Invoke(() => { MeterInfoList.Clear(); });
                                
                                using (var workbook = new XLWorkbook(filePath))
                                {
                                    var worksheet = workbook.Worksheet(1);
                                    // 遍历工作表中的所有行和列
                                    for (int row = 2; row <= worksheet.LastRowUsed().RowNumber(); row++)
                                    {
                                        MeterInfo meterInfo = new MeterInfo();
                                        for (int col = 1; col <= worksheet.LastColumnUsed().ColumnNumber(); col++)
                                        {
                                            // 读取单元格数据
                                            var cellValue = worksheet.Cell(row, col).Value;
                                            Console.WriteLine($"Row {row}, Col {col}: {cellValue}");
                                            switch (col)
                                            {
                                                case 1:
                                                    meterInfo.SeqNo = int.Parse((string)cellValue);
                                                    break;
                                                case 2:
                                                    meterInfo.CommuAddr = (string)cellValue;
                                                    break;
                                                case 3:
                                                    meterInfo.Baudrate = int.Parse((string)cellValue);
                                                    break;
                                                case 4:
                                                    meterInfo.ProtocolType = int.Parse((string)cellValue);
                                                    break;
                                                case 5:
                                                    meterInfo.Port = (string)cellValue;
                                                    break;
                                                case 6:
                                                    meterInfo.CommuCode = (string)cellValue;
                                                    break;
                                                case 7:
                                                    meterInfo.TarriffNum = (string)cellValue;
                                                    break;
                                                case 8:
                                                    meterInfo.UserType = (string)cellValue;
                                                    break;
                                                case 9:
                                                    meterInfo.WireMode = int.Parse((string)cellValue);
                                                    break;
                                                case 10:
                                                    meterInfo.RatedVoltage = (string)cellValue;
                                                    break;
                                                case 11:
                                                    meterInfo.RatedCurrent = (string)cellValue;
                                                    break;
                                                case 12:
                                                    meterInfo.CollectAddr = (string)cellValue;
                                                    break;
                                                case 13:
                                                    meterInfo.AssetNumber = (string)cellValue;
                                                    break;
                                                case 14:
                                                    meterInfo.Pt = (string)cellValue;
                                                    break;
                                                case 15:
                                                    meterInfo.Ct = (string)cellValue;
                                                    break;
                                                default:
                                                    break;
                                            }
                                        }
                                        Application.Current.Dispatcher.Invoke(() => { meterInfoList.Add(meterInfo); });
                                        
                                    }
                                }
                                MeterInfoService.Insert(MeterInfoList.ToList());
                            });
                        }

                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                    
                });
            }
        }

        public RelayCommand AddMeterInfoCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var vm = ServiceLocator.Current.GetInstance<AddOrUpdateMeterInfoViewModel>();
                    AddOrUpdateMeterInfoViewModel.MeterInfo = null;
                    vm.InitMeterInfo(MeterInfoList.Count > 0 ? MeterInfoList[MeterInfoList.Count - 1] : default);
                    AddOrUpdateMeterInfoView addOrUpdateMeterInfoView = new AddOrUpdateMeterInfoView();
                    if (addOrUpdateMeterInfoView.ShowDialog()==true)
                    {
                        
                    }
                });
            }
        }

        public RelayCommand EditMeterInfoCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    if (SelectedMeterInfo < 0)
                    {
                        return;
                    }
                    var vm = ServiceLocator.Current.GetInstance<AddOrUpdateMeterInfoViewModel>();
                    AddOrUpdateMeterInfoViewModel.MeterInfo = MeterInfoList[SelectedMeterInfo];
                    vm.LoadMeterInfo();
                    AddOrUpdateMeterInfoView addOrUpdateMeterInfoView = new AddOrUpdateMeterInfoView();
                    if (addOrUpdateMeterInfoView.ShowDialog() == true)
                    {
                        MeterInfoList = new ObservableCollection<MeterInfo>(MeterInfoList.OrderBy(item => item.SeqNo));
                    }
                });
            }
        }
        public RelayCommand DelectMeterInfoCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    if (SelectedMeterInfo<0)
                    {
                        return;
                    }
                    MeterInfoService.Delete(MeterInfoList[SelectedMeterInfo]);
                    MeterInfoList.RemoveAt(SelectedMeterInfo);
                    MeterTotalNumber = MeterInfoList.Count;
                });
            }
        }
        public RelayCommand<Window> CloseCommand
        {
            get
            {
                return new RelayCommand<Window>((w) =>
                {
                    w.DialogResult = true;
                });
            }
        }
        #endregion
    }

}
